<template>
  <div class="vir-table">
    <div class="vir-table-table">
      <el-table ref="table" :$ready="false" :row-key="rowKey" :data="insideTableData" @current-change="doChangeTableCurrent" @selection-change="doChangeTableSelection" @cell-click="doTableCellClick" @row-click="doTableRowClick" height="100%" :highlight-current-row="true" :border="true">
        <slot></slot>
      </el-table>
    </div>
    <div class="vir-table-page">
      <el-pagination :page-sizes="pageSizes" :layout="pageLayout" :page-count="insidePages" :current-page="insidePageNum" :page-size="insidePageSize" :total="insideTotal" @size-change="doChangePageSize" @current-change="doChangePageCurrent" :pager-count="5" prev-text="上一页" next-text="下一页"></el-pagination>
    </div>
  </div>
</template>

<script lang="ts">
import { Component, Prop, Vue, Watch } from 'vue-property-decorator';
import session from '@/plugins/storage';
import Util from '@/util/util';

@Component
export default class VirTable extends Vue {
  @Prop({ required: true })
  private url!: string;

  @Prop({ default: () => 1 })
  private page!: number;

  @Prop({ default: () => null })
  private param!: any;

  @Prop({ default: () => 15 })
  private limit!: number;

  @Prop({ default: 'id', type: [String, Function] })
  private rowKey!: string | ((row: any) => any);

  @Prop({ default: () => [5, 10, 15, 20] })
  private pageSizes!: number[];

  @Prop({ default: () => 'prev, pager, next, sizes' })
  private pageLayout!: string;

  // 内部变量
  private insideTableData: any[] = []; // 数据列表

  private insidePages: number = 1; // 总页数
  private insidePageNum: number = 1; // 当前页码
  private insidePageSize: number = 15; // 每页条数

  private insideSize: number = 1; // 当前条数
  private insideTotal: number = 0; // 总条数

  private insideParam: any = {}; // 查询参数

  private currentRow?: any;
  private selectionRow: any[] = [];

  get table(): any {
    return this.$refs.table;
  }

  /** 加载表格数据 */
  public load(page?: number, limit?: number, param?: any): Promise<any> {
    return new Promise<any>((resolve, reject) => {
      this.$$loading.open('正在加载数据...');

      // 如果传入空就使用之前的值
      page = page || this.insidePageNum;
      limit = limit || this.insidePageSize;

      // 构造请求地址
      let url = this.url;
      if (url && url.indexOf('?') >= 0) {
        url = url + `&page=${page}&limit=${limit}`;
      } else if (url) {
        url = url + `?page=${page}&limit=${limit}`;
      }

      // 获取数据
      this.$http.doGet(url, param).then((res) => {
        const data = res.data;

        // 缓存查询参数
        this.insideParam = param;

        // 缓存页码信息
        this.insidePages = data.pages;
        this.insidePageNum = data.pageNum;
        this.insidePageSize = data.pageSize;

        // 缓存数据信息
        this.insideSize = data.size;
        this.insideTotal = data.total;

        // 数据表修改
        this.insideTableData = data.list;

        // 回调数据
        resolve(data.list);
      }).catch((err: any) => {
        reject(err);
      }).finally(() => {
        this.$$loading.close();
      });
    });
  }

  /** 重载数据 */
  public reload(): Promise<any> {
    return this.load(1, 15, this.param || {});
  }

  /** 获取指定行 */
  public getRow(row: number): any {
    if (0 <= row && row < this.insideTableData.length) {
      return this.insideTableData[row];
    } else {
      return undefined;
    }
  }

  /** 获取当前选择行 */
  public getCurrentRow(): any {
    return this.currentRow;
  }

  /** 设置当前选择行 */
  public setCurrentRow(row: number): void {
    if (0 <= row && row < this.insideTableData.length) {
      this.table.setCurrentRow(this.insideTableData[row]);
    }
  }

  /** 清空被选中行 */
  public clearSelection(): any {
    return this.table.clearSelection();
  }

  /** 获取被选中行 */
  public getSelectionRow(): any[] {
    return this.selectionRow || [];
  }

  /** 获取被选中行(KEY值) */
  public getSelectionKey(): any[] {
    return this.selectionRow.map((item: any) => {
      if (typeof (this.rowKey) === 'function') {
        return this.rowKey(item);
      } else {
        return item[this.rowKey];
      }
    });
  }

  /** 设置行被选中/取消选中 */
  public setSelectionRow(key: any, check: boolean): any {
    for (const item of this.insideTableData) {
      // 如果Rowkey是函数->判断值是否一致
      if (typeof (this.rowKey) === 'function' && this.rowKey(item) === key) {
        return this.table.toggleRowSelection(item, check);
      }

      // 如果Rowkey是字符串->判断值是否一致
      if (typeof (this.rowKey) === 'string' && item[this.rowKey] === key) {
        return this.table.toggleRowSelection(item, check);
      }
    }

    return false;
  }

  /** 组件创建时：从缓存中获取数据 & 注入实例到管理器 */
  private mounted() {
    // 加载缓存配置
    let cacheParam: any = session.getObj(this.key('p'));
    let cachePageNum: any = session.getAny(this.key('n'));
    let cachePageSize: any = session.getAny(this.key('s'));

    // 加载配置条件 & 参数过滤
    cacheParam = Object.assign(cacheParam || {}, this.param);
    cachePageSize = cachePageSize || this.limit || 15;
    cachePageNum = cachePageNum || this.page || 1;

    // 默认第一次加载数据
    this.load(cachePageNum, cachePageSize, cacheParam).then((data) => {
      this.$emit('table-page-init', cacheParam);
    });
  }

  /** 组件销毁时：将表单参数、分页信息存入缓存 */
  private destroyed() {
    session.save(this.key('p'), this.insideParam);
    session.save(this.key('n'), this.insidePageNum);
    session.save(this.key('s'), this.insidePageSize);
  }

  /** 缓存KEY */
  private key(k: string) {
    return `page-cache-${k}-${this.url}`;
  }

  /** 每页条数切换 */
  private doChangePageSize(limit: number) {
    this.load(1, limit, {}).then((d) => {
      this.$emit('table-page-size', limit);
    });
  }

  /** 页码切换 */
  private doChangePageCurrent(page: number) {
    this.load(page).then((d) => {
      this.$emit('table-page-num', page, d);
    });
  }

  /** 切换当前选择行 */
  private doChangeTableCurrent(currentRow: any, lastRow: any) {
    this.$emit('table-row-current', this.currentRow = currentRow, lastRow);
  }

  /** 改变被选中行 */
  private doChangeTableSelection(selectionRows: any[]) {
    this.$emit('table-row-selection', this.selectionRow = selectionRows);
  }

  /** 行被点击 */
  private doTableRowClick(row: any, event: any, column: any) {
    this.$emit('table-row-click', row, column, event);
  }

  /** 单元格被点击 */
  private doTableCellClick(row: any, column: any, cell: any, event: any) {
    this.$emit('table-cell-click', row, column, cell, event);
  }
}
</script>